package geppetto.phraseHMM.phraseExtraction;

import geppetto.cat.corpus.BilingualCorpus;
import geppetto.cat.corpus.BilingualCorpusWithPOS;
import geppetto.main.ControlPoints;
import geppetto.phraseHMM.WordTrie;
import geppetto.phraseHMM.alignmentInformationWriters.AlignmentInformationWriter;
import geppetto.phraseHMM.lexicalWeighting.AbstractLexicalWeightingCalculator;
import geppetto.phraseHMM.phraseExtraction.extractedphrase.ExtractedPhrasePair;
import geppetto.phraseHMM.phraseExtraction.extractedphrase.ExtractedPhrasePairWriter;
import geppetto.phraseHMM.phraseExtraction.extractedphrase.SentenceInfo;
import geppetto.phraseHMM.phraseExtraction.phraseAccepter.AbstractPhraseAccepter;
import geppetto.phraseHMM.phraseExtraction.sentencePair.PhrasePairCandidate;
import geppetto.phraseHMM.phraseExtraction.sentencePair.PhrasePairCandidateExtractor;
import geppetto.phraseProbability.PhraseProbabilityCalculator;
import geppetto.phraseScorer.AbstractPhraseScorer;
import geppetto.phraseTable.PhraseTable;
import geppetto.phraseTable.phrase.Phrase;
import geppetto.phraseTable.phrase.feature.LexicalWeightingFeature;
import geppetto.reordering.AbstractReorderingCalculator;
import geppetto.reordering.AlwaysMonoCalculator;
import geppetto.reordering.ReorderingInfo;
import geppetto.reordering.graph.ReorderingGraph;

import java.util.ArrayList;




public class GeneralPhraseExtraction {

	/**
	 * Temporary arrays to avoid the constant creation of arrays
	 * For a ginen duration it contains an array of that size
	 */ 
	static int[][] sourceTMPArray ;
	static int[][] targetTMPArray ;
	static public PhraseTable _posPhraseTable;

	/**
	 * General method for extracting phrases given a sentence pair 
	 * @param pt
	 * @param sentenceNumber
	 * @param sentenceSource
	 * @param foreingSentence
	 * @param sourceSentence
	 * @param maxTargetDuration
	 * @param maxSourceDuration
	 * @param model
	 * @param threshold
	 * @return
	 */
	@Deprecated
	public static void extractPhrasePairsFromSentence(
			int sentenceNumber, byte sentenceSource, int[] foreingSentence,
			int[] sourceSentence, int maxTargetDuration, int maxSourceDuration, 
			AbstractPhraseScorer scorer, AbstractPhraseAccepter accepter,
			ExtractedPhrasePairWriter writer) {


		int fSize = foreingSentence.length;
		int sSize = sourceSentence.length;

		/**
		 * Initialize the an auxiliar phrase table for the phrases extracted for this specific sentence
		 * Array for all source durations. Each one contains all phrases of that source duration. 
		 * Position maxSourceDuration+1 contains null phrases. 
		 */

		for (int foreignStartPos = 0; foreignStartPos < fSize; foreignStartPos++) {
			for (int foreingDuration = 1; foreingDuration <= maxTargetDuration; foreingDuration++) {
				int foreignEndPos = foreignStartPos + foreingDuration - 1;
				if (foreignEndPos < fSize) {
					int[] foreing = targetTMPArray[foreingDuration-1];
					for (int f = 0; f < foreingDuration; f++) {
						foreing[f] = foreingSentence[foreignStartPos + f];
					}
					for (int sourceStartPos = 0; sourceStartPos < sSize; sourceStartPos++) {
						for (int sourceDuration = 1; sourceDuration <= maxSourceDuration; sourceDuration++) {
							int sourceEndPos = sourceStartPos + sourceDuration
							- 1;
							if (sourceEndPos < sSize) {
								int[] source = sourceTMPArray[sourceDuration-1];
								for (int s = 0; s < sourceDuration; s++) {
									source[s] = sourceSentence[sourceStartPos
									                           + s];
								}	
								//Get phrase
								ExtractedPhrasePair epp = new ExtractedPhrasePair(source, foreing,sentenceNumber, sentenceSource, foreingSentence, sourceSentence,sourceStartPos, sourceEndPos,foreignStartPos, foreignEndPos);
								//Score phrase
								double score = scorer.getPhraseScore(epp);
								//See if phrase is accepted
								if(accepter.acceptPhrase(epp)){		
									epp.setScore(score);
									writer.write(epp);
								}
							}
						}
					}
				}
			}
		}
	}

	/**
	 * General method for extracting phrases given a sentence pair 
	 * @param pt
	 * @param sentenceNumber
	 * @param sentenceSource
	 * @param foreingSentence
	 * @param sourceSentence
	 * @param maxTargetDuration
	 * @param maxSourceDuration
	 * @param model
	 * @param threshold
	 * @return
	 */
	public static ExtractedPhrasePair[] extractPhrasePairsFromSentence(
			int sentenceNumber, byte sentenceSource, int[] foreingSentence,
			int[] sourceSentence, PhrasePairCandidateExtractor phrasePairCandidateExtractor, 
			AbstractPhraseScorer scorer, AbstractPhraseAccepter accepter,
			ExtractedPhrasePairWriter writer, AlignmentInformationWriter informationWriter) {
		PhrasePairCandidate[] candidatePairs = phrasePairCandidateExtractor.extractSentencePairs(foreingSentence, sourceSentence, sentenceNumber);
		ArrayList<ExtractedPhrasePair> extractedPhrasePairs = new ArrayList<ExtractedPhrasePair>();
		for(PhrasePairCandidate candidatePair : candidatePairs){
			int foreingSize = candidatePair.getTargetEndIndex() - candidatePair.getTargetStartIndex() + 1;
			int sourceSize = candidatePair.getSourceEndIndex() - candidatePair.getSourceStartIndex() + 1;
			int[] foreing = new int[foreingSize];
			int[] source = new int[sourceSize];
			for (int f = 0; f < foreingSize; f++) {
				foreing[f] = foreingSentence[candidatePair.getTargetStartIndex() + f];
			}
			for (int s = 0; s < sourceSize; s++) {
				source[s] = sourceSentence[candidatePair.getSourceStartIndex() + s];
			}			

			//Get phrase
			ExtractedPhrasePair epp = new ExtractedPhrasePair(source, foreing,sentenceNumber, sentenceSource, foreingSentence, sourceSentence,candidatePair.getSourceStartIndex(), candidatePair.getSourceEndIndex(), candidatePair.getTargetStartIndex(), candidatePair.getTargetEndIndex());
			//See if phrase is accepted
			if(accepter.acceptPhrase(epp)){
				epp.setScore(scorer.getPhraseScore(epp));
				//add alignmentInformation
				extractedPhrasePairs.add(epp);
			}
		}
		ExtractedPhrasePair[] extractedPhrasePairsArray = extractedPhrasePairs.toArray(new ExtractedPhrasePair[0]);
		SentenceInfo info = new SentenceInfo(sentenceNumber, foreingSentence, sourceSentence, extractedPhrasePairsArray);
		for(ExtractedPhrasePair epp : extractedPhrasePairs){
			epp.setSentenceInfo(info);
		}
		return extractedPhrasePairsArray;
	}
	
	public static void printPhrasePairs(ExtractedPhrasePair[] pairs, ExtractedPhrasePairWriter writer, AlignmentInformationWriter informationWriter){
		for(ExtractedPhrasePair epp : pairs){
			informationWriter.writeAlignmentInformation(epp);
			writer.write(epp);
		}		
	}

	public static void generateMosesExtractionFile(final BilingualCorpus corpus, byte sentenceSource,
			ControlPoints controlPoints){
		generateMosesExtractionFile(corpus, sentenceSource, controlPoints.getPhraseCandidateExtractor(), controlPoints.getPhraseScorer(), controlPoints.getPhraseAccepter(), controlPoints.getOutputWriter(), controlPoints.getAlignmentInfoWriter());
	}

	public static void generateMosesExtractionFile(final BilingualCorpus corpus, byte sentenceSource,
			PhrasePairCandidateExtractor phrasePairCandidateExtractor,
			AbstractPhraseScorer scorer, AbstractPhraseAccepter accepter, ExtractedPhrasePairWriter writer, AlignmentInformationWriter alignmentInfoWriter){

		writer.writeHeaders();
		int maxSrcLength = 0;
		int maxTarLength = 0;
		int numberOfSentences = corpus.getNumSentences(sentenceSource);
		int numberOfSentencesPerPrint = (int)Math.pow(10.0d, String.valueOf(numberOfSentences).length()-1);
		for (int i = 0; i < numberOfSentences; i++) {
			if(i % numberOfSentencesPerPrint == 0){
				System.err.println("processing sentences " + i + " to " + (i+numberOfSentencesPerPrint));
				System.gc(); System.gc(); System.gc(); System.gc();
			    System.gc(); System.gc(); System.gc(); System.gc();
			    System.gc(); System.gc(); System.gc(); System.gc();
			    System.gc(); System.gc(); System.gc(); System.gc();
			    System.err.println("used memory = " + (Runtime.getRuntime().totalMemory() -
			      Runtime.getRuntime().freeMemory()));
			}
			int[] foreingSentence = corpus.getForeignSentence(i,sentenceSource);
			int[] sourceSentence = corpus.getSourceSentence(i,sentenceSource);
			ExtractedPhrasePair[] extractedPhrases = extractPhrasePairsFromSentence(i,sentenceSource, foreingSentence,
					sourceSentence, phrasePairCandidateExtractor,
					scorer,accepter,
					writer, alignmentInfoWriter);
			printPhrasePairs(extractedPhrases, writer, alignmentInfoWriter);
			for(ExtractedPhrasePair pair : extractedPhrases){
				int srcLength = pair.getSourceEndPos()-pair.getSourceStartPos();
				int tarLength = pair.getForeignEndPos()-pair.getForeignStartPos();
				maxSrcLength = Math.max(srcLength, maxSrcLength);
				maxTarLength = Math.max(tarLength, maxTarLength);
			}
		}
		maxSrcLength++;
		maxTarLength++;
		writer.writeInfo("maxSourceSize", String.valueOf(maxSrcLength));
		writer.writeInfo("maxTargetSize", String.valueOf(maxTarLength));
	}

	@Deprecated
	public static void generateMosesExtractionFile(final BilingualCorpus corpus, byte sentenceSource,
			int maxTargetDuration, int maxSourceDuration, 
			AbstractPhraseScorer scorer, AbstractPhraseAccepter accepter, ExtractedPhrasePairWriter writer){

		generateStaticArrays(maxSourceDuration, maxTargetDuration);

		writer.initialize();
		writer.writeHeaders();

		for (int i = 0; i < corpus.getNumSentences(sentenceSource); i++) {
			int[] foreingSentence = corpus.getForeignSentence(i,sentenceSource);
			int[] sourceSentence = corpus.getSourceSentence(i,sentenceSource);
			extractPhrasePairsFromSentence(i,sentenceSource, foreingSentence,
					sourceSentence, maxTargetDuration, maxSourceDuration,
					scorer,accepter,
					writer);
		}

		writer.close();
	}

	protected static void generateStaticArrays(int maxSourceDuration, int maxTargetDuration){
		//Avoid constant array creation
		sourceTMPArray = new int [maxSourceDuration][];
		for(int i = 0; i < maxSourceDuration; i++){
			sourceTMPArray[i] = new int[i+1];
		}
		targetTMPArray = new int [maxTargetDuration][];
		for(int i = 0; i < maxTargetDuration; i++){
			targetTMPArray[i] = new int[i+1];
		}
	}

}
